﻿using System;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Windows;
using EzDesk.DesktopClient.Event;
using EzDesk.DesktopClient.Model;
using EzDesk.DesktopClient.PopupModule.ViewModel;
using EzDesk.DesktopClient.Storage;
using EzDesk.EventAggregation;
using EzDesk.Generic;
using EzDesk.Generic.Collections;
using EzDesk.Generic.WPF;
using Microsoft.Practices.Unity;

namespace EzDesk.DesktopClient.PopupModule.Contoller
{
    public class NotificationPopupController : IDisposable
    {
        private RangeCollection<INotificationPopupViewModel> _notificationPopupViewModes;
        private Window _mainWindow;
        private bool _isMoved = false;
        private EventSubscriptor<FeedPushArgs> _feedPushToken;
        private EventSubscriptor<MainWindowMoveArgs> _mainWindowMoveToken;
        private Timer _windowLocationTimer;
        private IUnityContainer _container;

        public NotificationPopupController(IUnityContainer moduleConainer)
        {
            _notificationPopupViewModes = new RangeCollection<INotificationPopupViewModel>();
            this._mainWindow = CacheStorage.Instance.Get<Window>("MainWindow");
            this._container = moduleConainer;
            InitEvent();
        }

        private void InitEvent()
        {
            _feedPushToken = FeedPushEvent.Instance.Subscribe(this.OnFeedPush);
            _mainWindowMoveToken = MainWindowMoveEvent.Instance.Subscribe(this.OnMainWindowMove);
        }


        private void OnMainWindowMove(MainWindowMoveArgs obj)
        {
            this._mainWindow = obj.MainWindow as Window;
            this._isMoved = true;

            InitWindowLocationTimer();
        }

        private void InitWindowLocationTimer()
        {
            if (_windowLocationTimer == null)
                _windowLocationTimer
                    = new Timer(context =>
                                {
                                    if (_isMoved)
                                    {
                                        Application.Current.Dispatcher.BeginInvoke(
                                            new Action(RefreshNotificatonLocation));
                                    }
                                }
                            , null, 100, 200);
        }

        private void OnFeedPush(FeedPushArgs obj)
        {
            if(_notificationPopupViewModes == null) return;
            obj.UpdateCollection.Foreach(ProcessFeedTypeFromNotificationToUpdate);
            obj.NotificationCollection.Foreach(ProcessPushNotification);
            
            RefreshNotificatonLocation();
        }

        private void RefreshNotificatonLocation()
        {
            if (_notificationPopupViewModes == null) return;

            const double offHeight = 11;
            const double offWidth = 70;
            Window lastWindow = null;

            for (int index = 0; index < _notificationPopupViewModes.Count; index++)
            {
                var viewWindow = _notificationPopupViewModes[index].View as Window;
                viewWindow.ToBeTop().Show();

                if (index == 0)
                {
                    if (_mainWindow.IsDisplayOnScreen())
                        viewWindow.ToBeside(_mainWindow, WindowPostionDirection.Left, offWidth, offHeight);
                    else
                        viewWindow.ToBesideScreen(ContentAlignment.TopRight);
                }
                else
                    viewWindow.ToBeside(lastWindow, WindowPostionDirection.Down);

                lastWindow = viewWindow;
            }

            _isMoved = false;
        }

        private void ProcessFeedTypeFromNotificationToUpdate(Feed feed)
        {
            var notificationItemViewModel = _notificationPopupViewModes.FirstOrDefault(uvm => uvm.FeedModel.FeedID == feed.FeedID);
            if (notificationItemViewModel != null)
            {
                notificationItemViewModel.DisableNotification();
            }
        }

        private void ProcessPushNotification(Feed u)
        {
            var viewModel = this._notificationPopupViewModes.FirstOrDefault(uvm => uvm.FeedModel.FeedID == u.FeedID);
            //如果界面已经存在
            if (viewModel != null)
            {
                //更新feed
                if (viewModel.FeedModel.UpdateOn != u.UpdateOn)
                {
                    _notificationPopupViewModes.Remove(viewModel);
                    var notificationPopupViewModel = _container.Resolve<INotificationPopupViewModel>().SetModel(u);
                    _notificationPopupViewModes.InsertItemAtFirst(notificationPopupViewModel);
                    notificationPopupViewModel.OnClosing += notificationPopupViewModel_OnClosing;
                }
                //从界面上移除feed
                else if (viewModel.FeedModel.LastChangeOn != u.LastChangeOn)
                {
                    if (!u.IsAvailable.Value || u.IsRead.Value)
                    {
                        viewModel.DisableNotification();
                    }
                }
            }
            //如果界面上不存在，是新的feed
            else
            {
                if (u.IsAvailable.Value && !u.IsRead.Value)
                {
                    var notificationPopupViewModel = _container.Resolve<INotificationPopupViewModel>().SetModel(u);
                    _notificationPopupViewModes.InsertItemAtFirst(notificationPopupViewModel);
                    notificationPopupViewModel.OnClosing += notificationPopupViewModel_OnClosing;
                }
            }
        }

        void notificationPopupViewModel_OnClosing(object sender, EventArgs e)
        {
            var notificationPopupViewModel = sender as NotificationPopupViewModel;
            notificationPopupViewModel.OnClosing -= notificationPopupViewModel_OnClosing;
            this._notificationPopupViewModes.Remove(notificationPopupViewModel);
        }



        public void Dispose()
        {
            _feedPushToken.Dispose();
            _mainWindowMoveToken.Dispose();

            foreach (var notificationPopupViewModel in _notificationPopupViewModes)
            {
                notificationPopupViewModel.OnClosing -= this.notificationPopupViewModel_OnClosing;
                notificationPopupViewModel.View.CloseNotificationView();
                ((IDisposable)notificationPopupViewModel).Dispose();
            }

            _notificationPopupViewModes = null;
            this._mainWindow = null;
        }
    }
}